package testjeu;

import org.newdawn.slick.Animation;
import org.newdawn.slick.Image;
import org.newdawn.slick.SlickException;
import org.newdawn.slick.Sound;
import org.newdawn.slick.SpriteSheet;


/**
 * Gestion du tank dirigé par le joueur, et de ses différents états
 * @author YoTsumi
 */
public class tank extends Jeu implements Constantes {
    
    
    private Image       tank;
    private Image 		tankRepos[]=new Image[8];  
    private Image		tankRotation;
    private SpriteSheet spriteTankTemp;
    private Animation   animTankAvance[]=new Animation[8]; /* index=Angle/45 */
    private Animation   animExplosion;
    private Image       bouclier;
    //private Animation   start;
    
    private Etat etat= Etat.Repos;
    
    private float vitesse=1f;
    private int vitesseRotation=1;
    
    private int caseX,caseY, frontiereX, frontiereY, destX, destY, lastX, lastY;
    private float reelX, reelY;
    
    private int angle, angleDest=0;
    private int angleSens=0;
    
    private int CasesRestantesInvincibilité=0;
    
    private Sound explosion;
    private int tmp=0;
    
    private int angleDepart;
    
    
    /**
     * Constructeur : cré un nouveau tank dirigeable dans la case définie
     * 
     * @param caseDepartX     Colonne du tank
     * @param caseDepartY     Ligne du tank
     * @throws org.newdawn.slick.SlickException
     */
    public tank(int caseDepartX, int caseDepartY) throws SlickException {
        
        tank = new Image("res/sprite_tank.png");
        /* Penser à réduire le nbre de sprites */
        for (int i=0; i<8; i++) {
            spriteTankTemp= new SpriteSheet(tank.getSubImage(0, 40*i, 40*2, 40), 40, 40);
            animTankAvance[i]=new Animation(spriteTankTemp,200);
            tankRepos[i]=spriteTankTemp.getSprite(0, 0);
        }
        
        spriteTankTemp=new SpriteSheet(tank.getSubImage(0, 40*8, 40*7, 40),40,40); /* pr anim */
        animExplosion=new Animation(spriteTankTemp, 300);
        
        bouclier = tank.getSubImage(2*40, 40*9, 40,40);
        
        caseX=frontiereX=destX=lastX=caseDepartX;
        caseY=frontiereY=destY=lastY=caseDepartY;
        
        reelX=cases.colToPxl(caseX)+20;
        reelY=cases.ligToPxl(caseY)+20;
        
        
        explosion = new Sound("res/explosio.wav");
       // start=new Animation(new SpriteSheet("res/Effets/5.png",40,40), 100);
    }
    
    /**
     * Dessine le tank suivant l'état qui le définis
     * 
     * @throws org.newdawn.slick.SlickException
     */
    public void dessiner() throws SlickException {
               
        // Effectue l'action en cours
        switch (etat) {
            case Mouvement:
                
                if ( angle>270 || (angle>=0 && angle <90) ) reelX+=vitesse;
                else if (angle>90 && angle <270)            reelX-=vitesse;
                if (cases.milieuCol((int)reelX))            caseX=destX;
                if (reelX>=882 || reelX<=276 )              caseX=-1;
                
                if (angle<180 && angle>0)                   reelY+=vitesse;
                else if (angle>180)                         reelY-=vitesse;
                if (cases.milieuLig((int)reelY))            caseY=destY;
                if (reelY>=659 || reelY<=54)                caseY=-1;
                
            break;
            
            case Rotation:
                
            	
            	
                if ((angle-angleDest)%360!=0) {
                    
                    if (angleSens==0) {
                        int delta=Math.abs(angleDest-angle);
                        if (delta==180) {
                            if (angle>=180) angleSens=-1;
                            else            angleSens=1;
                        }
                        else if (delta>=5*45 && angle>=5*45) angleSens=1;
                        else if (delta>=5*45 && angle<=2*45) angleSens=-1;
                        else if (angleDest>angle)          	 angleSens=1;
                        else                				 angleSens=-1;
                        angleDepart=angle;
                        tankRotation=tankRepos[angle/45];
                    } 
                
                    angle=(angle+angleSens*vitesseRotation)%360;
                    tankRotation.setRotation(angle-angleDepart);
                    
                }
                else  { angleSens=0; while (angle<0) angle+=360; this.avancer(); }
                

            break;
        }
        
        // Animation de spawn
        //start.draw(cases.colToPxl(startX), cases.ligToPxl(startY) );
        
        // On lance/arrête l'animation si le tank est au repos/en mouvement
        if (this.etat==Etat.Repos || this.etat==Etat.AttenteOrdre)  {
            for (int i=0; i<8; i++) animTankAvance[i].stop();
        }
        else {
            for (int i=0; i<8; i++) animTankAvance[i].start();
        }
        
        // Si le tank est entrain de tourner, on met une image fixe
        if (this.etat==Etat.Rotation) tankRotation.draw(reelX-20, reelY-20);
        else if (this.etat!=Etat.Anhilé) animTankAvance[angle%360/45].draw(reelX-20, reelY-20);
        
        // Si le tank est détruit, on affiche l'explosion par dessus
        if (this.etat==Etat.Détruit || this.etat==Etat.Anhilé) {
            animExplosion.draw(reelX-20, reelY-20);
            animExplosion.stopAt(3);
            if (animExplosion.getFrame()==3) this.etat=Etat.Anhilé;
        }
        else if (CasesRestantesInvincibilité>0) {
            bouclier.draw(reelX-20, reelY-20);
        }
        
    }
    
    
    
    
    /**
     * Action du tank : Avancer d'une case
     */
    public void avancer() {
        etat=Etat.Mouvement;
        
        
        if      (angle==0)    destX=caseX+1;
        else if (angle==180)  destX=caseX-1;
        else if (angle==90)   destY=caseY+1;
        else if (angle==270)  destY=caseY-1;
        else if (angle==45) { destX=caseX+1; 
                              destY=caseY+1; }
        else if (angle==135){ destX=caseX-1; 
                              destY=caseY+1; }
        else if (angle==225){ destX=caseX-1; 
                              destY=caseY-1; }
        else if (angle==315){ destX=caseX+1; 
                              destY=caseY-1; }
        else System.out.println("Angle error !!"); 

    }
    
    
    /**
     * Action du tank : changer de direction
     * @param dir   Le nouvel angle que le tank doit avoir
     */
    public void direction (int dir) {
        angleDest=dir;
        etat=Etat.Rotation;
    }
    
    /**
     * Action du tank : Tir simple
     */
    public void tirer() {
        etat=Etat.Tir;
    }
    
    /**
     * Action du tank : Tir de 4 missiles
     */
    public void tirer4() {
        etat=Etat.Tir;
    }
    
    /**
     * Action du tank : Bouclier d'invincibilité
     * @param cases     Le nombre de cases durant laquelle l'invincibilité restera active
     */
    public void invincible(int cases) {
        CasesRestantesInvincibilité=cases+1;
    }
    
    /**
     * Appellée à chaque fois que le tank rentre dans une nouvelle case, 
     * permet de décrémenter le compteur de cases d'invincibilité
     */
    public void nouvelleCase() {
        CasesRestantesInvincibilité--;
    }
    
    /**
     * Action du tank : Explose !
     * @throws org.newdawn.slick.SlickException
     */
    public void explosion() throws SlickException {
        explosion.play();
        this.etat=Etat.Détruit;
    }
    
    
    
    /**
     * Vérifie si le tank est à l'arrêt, c'est à dire dans un état de Repos.
     * @return  Vrai si le tank est arrété.
     */
    public boolean estArreté() {
        return etat==Etat.Repos;
    }
    /**
     * Vérifie si le tank est détuit, c'està dire à l'état détruit ou anhilé ( sprite modifié )
     * @return Vrai si le tank est détruit.
     */
    public boolean estDétruit() {
        return etat==Etat.Détruit || etat==Etat.Anhilé;
    }
    /**
     * Vérifie si le tank est entrain de tirer ( tir ou tir4 )
     * @return Vrai si le tank a un tir en cours
     */
    public boolean tirEnCours() {
        return etat==Etat.Tir;
    }
    /**
     * Vérifie si le tank est invincible à l'instant donné
     * @return Vrai si le tank est invincible
     */
    public boolean estInvincible() {
        return CasesRestantesInvincibilité>0;
    }
    
    /**
     * Vérifie si le tank est entré dans une nouvelle case
     * @return Vrai si le tank entre dans une nouvelle case
     */
    public boolean estDansNouvelleCase() {        
        if (caseX!=frontiereX || caseY!=frontiereY) {
        	lastX=frontiereX; lastY=frontiereY;
            frontiereX=caseX; frontiereY=caseY;
            CasesRestantesInvincibilité--;
            tmp++;
            return true;
        } 
        return false;
    }
    
    /**
     * Vérifie si le tank a terminé son mouvement en cours ( rotation principalement )
     * @return Vrai si le tank a terminé son mouvement
     */
    public boolean aTerminéMouvement() {
        return etat==Etat.FinMouvement;
    }
        
    
    
    /**
     * Retourne la colone actuellement occupée par le centre du tank
     * @return Colonne du tank (1-15)
     */
    public int tankCol() {
        return caseX;
    }
    /**
     * Retourne la ligne actuellement occupée par le centre du tank
     * @return Ligne du tank (1-15)
     */
    public int tankLig() {        
        return caseY;
    }
    
    public int tankLastCol() {
    	return lastX;
    }
    
    public int tankLastLig() {
    	return lastY;
    }
    
    /**
     * Retourne l'angle actuel du tank
     * @return Angle du tank (0-360)
     */
    public int tankAngle() {
        return angle;
    }
    
    
    
    
    /**
     * Définis l'état courant du tank
     * @param nouvEtat  Le nouveau état du tank
     */
    public void setEtat(Etat nouvEtat) {
        etat=nouvEtat;
    }
    /**
     * Définis l'angle courant et immédiat du Tank
     * @param ang    L'angle désiré pour le tank
     */
    public void setAngle (int ang) {
        angle=angleDest=ang;
    }
    
    
 

}
